---
title: Provider
---

import CodeBlock from "@theme/CodeBlock";
import todo from "/docs/providers/provider/todo";
import completedTodos from "/docs/providers/provider/completed_todos";
import todosConsumer from "!!raw-loader!/docs/providers/provider/todos_consumer.dart";
import unoptimizedPreviousButton from "/docs/providers/provider/unoptimized_previous_button";
import optimizedPreviousButton from "/docs/providers/provider/optimized_previous_button";
import { trimSnippet, AutoSnippet } from "../../../../../src/components/CodeSnippet";

:::caution
The content of this page may be outdated.  
It will be updated in the future, but for now you may want to refer to the content
in the top of the sidebar instead (introduction/essentials/case-studies/...)
:::

`Provider` is the most basic of all providers. It creates a value... And that's about it.

`Provider` is typically used for:

- caching computations
- exposing a value to other providers (such as a `Repository`/`HttpClient`).
- offering a way for tests or widgets to override a value.
- reducing rebuilds of providers/widgets without having to use `select`.

## Using `Provider` to cache computations

`Provider` is a powerful tool for caching synchronous operations when combined
with [ref.watch].

An example would be filtering a list of todos.
Since filtering a list could be slightly expensive, we ideally do not want to
filter our list of todos whenever our application re-renders.
In this situation, we could use `Provider` to do the filtering for us.

For that, assume that our application has an existing [NotifierProvider]
which manipulates a list of todos:

<AutoSnippet language="dart" {...todo}></AutoSnippet>

From there, we can use `Provider` to expose the filtered list of todos, showing
only the completed todos:

<AutoSnippet language="dart" {...completedTodos}></AutoSnippet>

With this code, our UI is now able to show the list of the completed todos
by listening to `completedTodosProvider`:

<CodeBlock>{trimSnippet(todosConsumer)}</CodeBlock>

The interesting part is, the list filtering is now cached.

Meaning that the list of completed todos will not be recomputed until
todos are added/removed/updated, even if we are reading the list of completed
todos multiple times.

Note how we do not need to manually invalidate the cache when the list of todos
changes. `Provider` is automatically able to know when the result must be recomputed
thanks to [ref.watch].

## Reducing provider/widget rebuilds by using `Provider`

A unique aspect of `Provider` is that even when `Provider` is recomputed
(typically when using [ref.watch]), it will not update the widgets/providers
that listen to it unless the value changed.

A real world example would be for enabling/disabling previous/next buttons
of a paginated view:

![stepper example](https://user-images.githubusercontent.com/134939/47580830-31263a00-d950-11e8-9b61-0eaddab2709e.png)

In our case, we will focus specifically on the "previous" button.
A naive implementation of such button would be a widget which obtains the
current page index, and if that index is equal to 0, we would disable the button.

This code could be:

<AutoSnippet language="dart" {...unoptimizedPreviousButton}></AutoSnippet>

The issue with this code is that whenever we change the current page, the "previous"
button will rebuild.  
In the ideal world, we would want the button to rebuild only when changing between
activated and deactivated.

The root of the issue here is that we are computing whether the user is
allowed to go to the previous page directly within the "previous" button.

A way to solve this is to extract this logic outside of the widget and into a `Provider`:

<AutoSnippet language="dart" {...optimizedPreviousButton}></AutoSnippet>

By doing this small refactoring, our `PreviousButton` widget will no longer
rebuild when the page index changes thanks to `Provider`.

From now on when the page index changes, our `canGoToPreviousPageProvider` provider
will be recomputed. But if the value exposed by the provider does not change,
then `PreviousButton` will not rebuild.

This change both improved the performance of our button and had the interesting
benefit of extracting the logic outside of our widget.

[ref.watch]: ../concepts/reading#using-refwatch-to-observe-a-provider
[notifierprovider]: ./notifier_provider
